#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Unit tests for applications.py
import applications
import generic_mock
import os
import unittest
import services

class TestTokenRing(unittest.TestCase):
    
    def setUp(self):
        self.protocol_ = generic_mock.GenericMock()
        self.services_ = generic_mock.GenericMock()
        self.random_ = generic_mock.GenericMock()
        self.ring_ = services.virtualring()
        self.timer_ = generic_mock.GenericMock()
        self.services_.StubForTesting(
            'virtualring', lambda: self.ring_)
        self.services_.StubForTesting(
            'timer', lambda _: self.timer_)
        self.protocol_.DoNotLog('set_callback')
        self.protocol_.DoNotLog('get_pid')
        self.protocol_.DoNotLog('get_hosts')

    def testBasicRunPID1(self):
        msgs = [(4, [0, 4, -1]), 
                (4, [0, 6, 3])]
        states = []
        self.random_.StubForTesting('sample', lambda _x, _y: [3])
        self.random_.StubForTesting('randint', lambda _x, _y: 5)
        self.protocol_.StubForTesting('get_pid', lambda: 1)
        self.protocol_.StubForTesting('get_hosts', lambda: (1, 2, 3, 4))
        self.protocol_.StubForTesting('recv_message', lambda: msgs.pop(0))
        self.ring_.set_comm(self.protocol_)
        tr = applications.TokenRing(
            protocol=self.protocol_, services=self.services_,
            state_size = 1, step_count = 3, max_count = 6, 
            random=self.random_)
        self.protocol_.StubForTesting(
            'take_basic_checkpoint', 
            lambda: states.append(tr.State()))    
        tr.Run()
        self.assertEqual(
            self.protocol_, 
            [('take_basic_checkpoint', (), {}), 
             ('send_message', (2, [0, 1, -1]), {}), 
             ('recv_message', (), {}), 
             ('send_message', (2, [0, 5, -1]), {}), 
             ('send_message', (3, [1, None]), {}), 
             ('recv_message', (), {}), 
             ('send_message', (2, [0, 7, 3]), {}), 
             ('close_channel', (2,), {}), 
             ('close_channel', (3,), {}), 
             ('close_channel', (4,), {})])
        self.assertEqual(msgs, [])
        self.assertEqual(states, [[1, [5]]])

    def testBasicRunPIDNot1WithPayload(self):
        msgs = [(4, [0, 2, -1]), 
                (4, [0, 5, -1])]
        states = []
        self.random_.StubForTesting('sample', lambda _x, _y: [4])
        self.random_.StubForTesting('randint', lambda _x, _y: 5)
        self.protocol_.StubForTesting('get_pid', lambda: 2)
        self.protocol_.StubForTesting('get_hosts', lambda: (1, 2, 3, 4))
        self.protocol_.StubForTesting('recv_message', lambda: msgs.pop(0))
        self.ring_.set_comm(self.protocol_)
        tr = applications.TokenRing(
            protocol=self.protocol_, services=self.services_,
            state_size = 1, step_count = 3, max_count = 6, 
            random=self.random_, payload=lambda: 'Payload')
        self.protocol_.StubForTesting(
            'take_basic_checkpoint', 
            lambda: states.append(tr.State()))    
        tr.Run()
        self.assertEqual(
            self.protocol_, 
            [('take_basic_checkpoint', (), {}), 
             ('recv_message', (), {}), 
             ('take_basic_checkpoint', (), {}), 
             ('send_message', (3, [0, 3, -1]), {}), 
             ('send_message', (4, [1, 'Payload']), {}), 
             ('recv_message', (), {}), 
             ('send_message', (3, [0, 6, 2]), {}), 
             ('close_channel', (1,), {}), 
             ('close_channel', (3,), {}), 
             ('close_channel', (4,), {})])
        self.assertEqual(msgs, [])
        self.assertEqual(states, [[1, [5]], [3, [5]]])

    def testState(self):
        r=[1, 2, 3, 4, 100, 5]
        self.random_.StubForTesting('randint', lambda _x, _y: r.pop(0))
        self.protocol_.StubForTesting('get_pid', lambda: 2)
        self.protocol_.StubForTesting('get_hosts', lambda: (1, 2, 3, 4))
        tr = applications.TokenRing(
            protocol=self.protocol_, services=self.services_,
            state_size = len(r), step_count = 3, max_count = 6, 
            random=self.random_, payload=lambda: 'Payload')
        tr.counter_ = 545
        self.assertEqual(tr.State(),
                         [545, [1, 2, 3, 4, 100, 5]])


if __name__ == '__main__':
    unittest.main()
    
